package cn.tedu.vue_master.service.impl;

import cn.tedu.vue_master.exception.ACServiceException;
import cn.tedu.vue_master.mapper.UserMapper;
import cn.tedu.vue_master.pojo.user.dto.UserAddDTO;
import cn.tedu.vue_master.pojo.user.dto.UserLoginInfoDTO;
import cn.tedu.vue_master.pojo.user.model.User;
import cn.tedu.vue_master.restful.ServiceCode;
import cn.tedu.vue_master.security.MyUserDetails;
import cn.tedu.vue_master.service.IUserService;
import com.alibaba.fastjson.JSON;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;

import java.util.Collection;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

@Slf4j
@Service
public class UserServiceImpl implements IUserService {

    @Value("${vue_master.jwt.secret-key}")
    private String secretKey;

    @Autowired
    private AuthenticationManager authenticationManager;
    @Autowired
    private UserMapper userMapper;
    @Autowired
    private PasswordEncoder passwordEncoder;

    @Override
    public String login(UserLoginInfoDTO userLoginInfoDTO) {

        log.debug("开始处理【登录认证】的业务，参数：{}", userLoginInfoDTO);

        Authentication authentication = new UsernamePasswordAuthenticationToken(
                userLoginInfoDTO.getUsername(),
                userLoginInfoDTO.getPassword());
        Authentication authenticateResult =
                authenticationManager.authenticate(authentication);
        log.debug("Spring Security已经完成认证，且认证通过，返回的结果：{}", authenticateResult);
        log.debug("返回认证信息中的当事人（Principal）类型：{}", authenticateResult.getPrincipal().getClass().getName());
        log.debug("返回认证信息中的当事人（Principal）数据：{}", authenticateResult.getPrincipal());

        // 从认证返回结果中取出当事人信息
        MyUserDetails principal = (MyUserDetails) authenticateResult.getPrincipal();
        Long id = principal.getId();
        log.debug("认证信息中的用户id：{}", id); // 新增
        String username = principal.getUsername();
        log.debug("认证信息中的用户名：{}", username);


        Collection<GrantedAuthority> authorities = principal.getAuthorities();
        log.debug("认证信息中的权限：{}", authorities);
        String authorityListString = JSON.toJSONString(authorities);
        log.debug("认证信息中的权限转换为JSON字符串：{}", authorityListString);

        //生成jwt
        Map<String, Object> claims = new HashMap<>();
        claims.put("id", id);
        claims.put("username", username);
        claims.put("authorities", authorityListString); // 新增

        // JWT的过期时间
        Date expiration = new Date(System.currentTimeMillis() + 60 * 24 * 60 * 60 * 1000);
        log.debug("即将生成JWT数据，过期时间：{}", expiration);

        // JWT的组成：Header（头：算法和Token类型）、Payload（载荷）、Signature（签名）
        String jwt = Jwts.builder()
                // Header
                .setHeaderParam("alg", "HS256")
                .setHeaderParam("typ", "JWT")
                // Payload
                .setClaims(claims)
                .setExpiration(expiration)
                // Signature
                .signWith(SignatureAlgorithm.HS256, secretKey)
                .compact();
        log.debug("已经生成JWT数据：{}", jwt);
        return jwt;
    }

    @Override
    public void register(UserAddDTO userAddDTO) {
        log.debug("开始处理【添加用户】的业务，参数：{}", userAddDTO);
        String username = userAddDTO.getUsername();
        log.debug("检查用户名【{}】是否被占用……", username);
        // 调用Mapper对象的countByUsername()根据用户名统计管理员账号的数量
        int countByUsername = userMapper.countByUsername(username);
        // 判断统计结果是否大于0
        if (countByUsername > 0) {
            // 是：抛出ServiceException（ERR_CONFLICT）
            String message = "添加用户失败，用户名【" + username + "】已经被占用！";
            log.warn(message);
            throw new ACServiceException(ServiceCode.ERR_CONFLICT, message);
        }

        // 从参数中取出手机号码
        String phone = userAddDTO.getPhone();
        log.debug("检查手机号码【{}】是否被占用……", phone);
        // 调用Mapper对象的countByPhone()根据手机号码统计管理员账号的数量
        int countByPhone = userMapper.countByPhone(phone);
        // 判断统计结果是否大于0
        if (countByPhone > 0) {
            // 是：抛出ServiceException（ERR_CONFLICT）
            String message = "添加用户失败，手机号码【" + phone + "】已经被占用！";
            log.warn(message);
            throw new ACServiceException(ServiceCode.ERR_CONFLICT, message);
        }

        User user = new User();
        BeanUtils.copyProperties(userAddDTO, user);
        user.setLevel(4);
        user.setCurrentExperience(0);

        // 取出Admin对象中的密码，将其加密，再存入到Admin对象中
        String rawPassword = user.getPassword();
        String encodedPassword = passwordEncoder.encode(rawPassword);
        user.setPassword(encodedPassword);
        // 调用Mapper对象的insert()插入管理员数据，并获取返回值
        log.debug("即将插入用户数据：{}", user);
        int rows = userMapper.addUser(user);
        // 判断返回值是否不等于1
        if (rows != 1) {
            // 是：抛出ServiceException（ERR_INSERT）
            String message = "添加管理员失败，服务器忙，请稍后再尝试！[错误代码：1]";
            log.warn(message);
            throw new ACServiceException(ServiceCode.ERR_INSERT, message);
        }
    }
}
